package main

/*
gRPC主要有4种请求和响应模式，
简单模式(Simple RPC)：客户端发起请求并等待服务端响应。
服务端流式（Server-side streaming RPC）：客户端发送请求到服务器，拿到一个流去读取返回的消息序列。 客户端读取返回的流，直到里面没有任何消息。
客户端流式（Client-side streaming RPC）：与服务端数据流模式相反，这次是客户端源源不断的向服务端发送数据流，而在发送结束后，由服务端返回一个响应。
双向流式（Bidirectional streaming RPC）：双方使用读写流去发送一个消息序列，两个流独立操作，双方可以同时发送和同时接收。
*/
import (
	"fmt"
	"google.golang.org/grpc"
	"learn_grpc/3_stream_grpc_test/proto"
	"net"
	"sync"
	"time"
)

const PORT = ":50052"

type Server struct{}

// 业务逻辑代码

// 服务端数据流模式方法业务逻辑实现
func (s *Server) GetStream(req *proto.StreamReqData, res proto.Greeter_GetStreamServer) error {
	// 由于要实时发送数据给客户端，所以调用定义好的send()方法，一调用客户端就能收到
	i := 0
	for {
		i++
		_ = res.Send(&proto.SreamResData{
			Data: fmt.Sprintf("%v", time.Now().Unix()),
		})
		time.Sleep(time.Second)
		if i > 10 {
			break
		}
	}
	return nil

}

// 客户端数据流模式（Client-side streaming RPC）
func (s *Server) PutStream(cliStr proto.Greeter_PutStreamServer) error {
	//客户端流模式，接收客户端不停发来的数据流
	for {
		if a, err := cliStr.Recv(); err != nil {
			fmt.Println("recv err:", err)
			break
		} else {
			fmt.Println("recv data:", a.GetData())
		}
	}
	return nil
}

// 双向数据流模式（Bidirectional streaming RPC）
func (s *Server) AllStream(allStr proto.Greeter_AllStreamServer) error {
	wg := sync.WaitGroup{}
	wg.Add(2)
	//接收数据的
	go func() {
		defer wg.Done()
		for {
			a, err := allStr.Recv()
			if err != nil {
				fmt.Println("recv err:", err)
			}
			fmt.Println("recv client data:", a.Data)
		}
	}()
	//发送数据的
	go func() {
		i := 0
		defer wg.Done()

		for {
			i++
			_ = allStr.Send(&proto.SreamResData{Data: fmt.Sprintf("我是服务器-%d", i)})
			time.Sleep(time.Second)
		}

	}()
	wg.Wait()
	return nil
}

func main() {
	//实例化一个server
	service1 := grpc.NewServer()
	//将业务逻辑注册到server，
	proto.RegisterGreeterServer(service1, &Server{})
	//启动实例
	listener, err := net.Listen("tcp", PORT)
	if err != nil {
		panic(err)
	}
	service1.Serve(listener) //启动端口
}
